package br.pucrio.inf.tamdera;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;

import br.pucrio.inf.TamderaStandaloneSetup;
import br.pucrio.inf.tamdera.mapping.ConceptMappingManagement;
import br.pucrio.inf.tamdera.measurement.MeasurementManager;
import br.pucrio.inf.tamdera.prolog.PrologRepresentationManager;
import br.pucrio.inf.validation.TamderaJavaValidator;

public class TamderaSpecManager 
{

	public TamderaSpecManager(String specFilePath, 
			String metricFilePath, String prologProjectFilePath, TamderaController controller) {
		super();
		this.specFilePath = specFilePath;
		this.controller = controller;
		this.prologManager = new PrologRepresentationManager( prologProjectFilePath );
		this.measurementManager = new MeasurementManager( metricFilePath );
		/* it parses the specification in order to set the value of spec before sending it to the concept mapper*/
		parser();

		this.mappingManager = new ConceptMappingManagement(spec,  prologManager);
	}

	/* root element of the AST */
	private RulesSpecification spec;

	/*path of the specification file (i.e. nameoffile.rules)*/
	private String specFilePath;


	private PrologRepresentationManager prologManager; 

	/* controller is used to forward logs, errors to gui*/
	private TamderaController controller;

	/* responsible for mapping the specified concepts into code elements */
	private ConceptMappingManagement mappingManager;
	
	/* manager containting the collected metrics*/
	private MeasurementManager measurementManager;
	/** 
	 * it parsers rulesSpecificationFilePath
	 * */
	private void parser (  ) 
	{
		new TamderaStandaloneSetup().createInjectorAndDoEMFRegistration();
		ResourceSet rs = new ResourceSetImpl();
		Resource resource = rs.getResource(URI.createURI( specFilePath ), true);
		RulesSpecification model = (RulesSpecification) resource.getContents().get(0);
		spec = model;

		/* validation */
		TamderaJavaValidator.checkUniqueNamesOfConcepts( spec );
	}

	
	private List<String> checkConformanceOfAntiErosionRules() 
	{
		List<String> result = new ArrayList<String>();

		HashMap<String, List<String>> conceptsMapping = mappingManager.doMap();

		/*Passa para modulo de Prolog*/
		try 
		{
			prologManager.generateMappingPrologFile( conceptsMapping );
			List<QueryReportBean> reports = prologManager.checkDependencyRules( spec );

			//TODO mover esse codigo para o controller e fazer devida apresentacao
			for (QueryReportBean report : reports )
			{
				System.out.println();
				System.out.println( report.getMessage() );
				
				result.add( report.getMessage() );
				if (! report.isSuccessfullyChecked())
				{
					for ( String violation : report.getViolations() )
					{
						result.add( violation );
						System.out.println( violation );
					}
				}
			}

		} 
		catch (IOException e) 
		{
			e.printStackTrace();
			TamderaException except = new TamderaException("The system was not able to generate the concept mapping file");
			throw except;
		}
		return result;
	}
	
	/**
	 * It verifies the conformance of design rules.
	 * @return
	 */
	public List<String> checkConformanceOfDesignRules() {

		List<String> resultErosion = checkConformanceOfAntiErosionRules();
		
		List<String> resultDrift = checkConformanceOfAntiDriftRules();
		
		List<String> result = new ArrayList<String>();
		
		result.addAll( resultErosion );
		result.addAll( resultDrift );
		
		return result;
	}

	/**
	 * 
	 * @return
	 */
	private List<String> checkConformanceOfAntiDriftRules() {
		
		List<String> resultDrift = new ArrayList<String>();
		Hashtable<String, Hashtable<String, Double>> measures = measurementManager.getMeasures();
		
		try {
			
			prologManager.generateMeasureMappingPrologFile( measures );
			
			List<QueryReportBean> reports = prologManager.checkDriftRules( spec );

			//TODO mover esse codigo para o controller e fazer devida apresentacao
			for (QueryReportBean report : reports )
			{
				System.out.println();
				System.out.println( report.getMessage() );
				
				resultDrift.add( report.getMessage() );
				if (! report.isSuccessfullyChecked())
				{
					for ( String violation : report.getViolations() )
					{
						resultDrift.add( violation );
						System.out.println( violation );
					}
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
			TamderaException except = new TamderaException("The system was not able to generate the property mapping file");
			throw except;
		}
		
		return resultDrift;
	}


	public List<String> checkConsistencyOfDesignRules() 
	{
		List<String> result = new ArrayList<String>();
		try 
		{
			prologManager.generateDesignRulesLogicalFacts( spec );
			List<QueryReportBean> reports = prologManager.checkConsistencyOfAntiErosionRules();
			for (QueryReportBean report : reports )
			{
				System.out.println();
				System.out.println( report.getMessage() );
				
				result.add( report.getMessage() );
				if (! report.isSuccessfullyChecked())
				{
					for ( String violation : report.getViolations() )
					{
						result.add( violation );
						System.out.println( violation );
					}
				}
			}
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
			TamderaException except = new TamderaException("The system was not able to generate the anti erosion rules file");
			throw except;
		}
		
		return result;
	}
}
